#pragma once 
#include<sys/epoll.h>
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include"threadpool.hpp"
#include"util.hpp"
#include"log.hpp"
#include"task.hpp"
using namespace std;

#define MAX_NUM 64

class Reactor
{  
  private:
    int epollfd;
    int linsent_sock;
    static Reactor* ptr;
  private:
    Reactor(int _epollfd,int _linsent_sock)
      :epollfd(_epollfd)
      ,linsent_sock(_linsent_sock)
    {}
  public:
    static Reactor* GetReactorObj(int _epollfd,int _linsent_sock)
    {
      if(ptr==nullptr)
        ptr=new Reactor(_epollfd,_linsent_sock);
      return ptr;
    }
  public:
    //添加事件
    void Addfd(int sock,uint32_t ev)
    {
      epoll_event event;
      event.data.fd=sock;
      event.events=0;
      event.events|=ev;

      if(epoll_ctl(epollfd,EPOLL_CTL_ADD,sock,&event)<0)
      {
        LOG(INFO,"EPOLL_CTL_ADD SUCCEED");
      }
    }

    //删除事件
    void disfd(int sock)
    {
      if(epoll_ctl(epollfd,EPOLL_CTL_DEL,sock,nullptr)<0)
      {
        LOG(ERROR,"EPOLL_CTL_DEL");
      }
    }
    //修改事件
    void Modfd(){}

    //事件分派器
    void Distribute()
    { 
      struct epoll_event event[MAX_NUM];
      int num=epoll_wait(epollfd,event,MAX_NUM,-1);
      
      for(int i=0;i<num;++i)
      {
        if(event[i].data.fd==linsent_sock)
        {
          //有新连接
          struct sockaddr_in oth; 
          socklen_t len=sizeof(oth);
          int sock=accept(linsent_sock,(struct sockaddr*)&oth,&len);
          if(sock<0){
            LOG(ERROR,"ACCEPT");
          }
          LOG("INFO","ACCEPT SUCCEED");
          SetNonBlock(sock);          
          Addfd(sock,EPOLLIN|EPOLLET);
          
          //Task t(sock);
          //ThreadPool* p= ThreadPool::GetThreadPoolObj();
          //p->Push(t);
        }
        else if(event[i].events & EPOLLIN)
        {
          //读事件,放入任务队列，又空闲线程来完成任务
          int sock=event[i].data.fd; 
          Task t(sock);
          ThreadPool* p=ThreadPool::GetThreadPoolObj();
          p->Push(t);
        }
      }
  
    }

    ~Reactor()
    {}
};
Reactor* Reactor::ptr=nullptr;
